package com.adam.example.service;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.GetResponse;
import co.elastic.clients.json.JsonData;
import com.adam.example.entity.repository.Book;
import com.adam.example.repository.BookRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.index.Settings;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;

@Service
public class TestService implements InitializingBean {

    private static final Logger LOGGER = LoggerFactory.getLogger(TestService.class);

    @Autowired
    private BookRepository bookRepository;
    @Autowired
    private ElasticsearchClient elasticsearchClient;
    @Autowired
    private ElasticsearchOperations elasticsearchOperations;  //同时继承自DocumentOperations(Id-based)、SearchOperations(Query-based)
    @Autowired
    private DocumentOperations documentOperations;
    @Autowired
    private SearchOperations searchOperations;

    @Override
    public void afterPropertiesSet() throws Exception {
        IndexOperations indexOperations = elasticsearchOperations.indexOps(Book.class);
        Settings settings = indexOperations.getSettings();
        LOGGER.debug("Settings {}", settings);

        Book book = bookRepository.findById(5L).orElse(null);
        LOGGER.debug("Book[2]:{}", book);

        LOGGER.debug("");
        SearchHits<Book> searchHits = bookRepository.findHighlightedBooksByTitleOrDescription("java", "java");
        iterateSearchHits(searchHits, (searchHit,i) -> {
            Book book1 = searchHit.getContent();
            Map<String, List<String>> highlightFieldsMap = searchHit.getHighlightFields();
            LOGGER.debug("result[{}] object={} highlight={}", i, book1, highlightFieldsMap);
            return null;
        });

        SearchPage<Book> searchPage = bookRepository.findByBoolQuery("python", "python", PageRequest.of(0, 10));
        LOGGER.debug("");
        LOGGER.debug("number of elements: {}", searchPage.getNumberOfElements());
        SearchHits<Book> searchHits1 = searchPage.getSearchHits();
        iterateSearchHits(searchHits1, (searchHit, i) -> {
            Book book1 = searchHit.getContent();
            LOGGER.debug("result[{}] object={}", i, book1);
            return null;
        });

        GetResponse<com.adam.example.entity.client.Book> getResponse = elasticsearchClient.get(builder -> builder
                .index("test_books").id("6"), com.adam.example.entity.client.Book.class
        );
        LOGGER.debug("ElasticsearchClient get {}", getResponse.source());

        Book book1 = elasticsearchOperations.get("5", Book.class);
        LOGGER.debug("ElasticsearchOperations get {}", book1);
        SearchHits<Book> searchHits2 = elasticsearchOperations.search(NativeQuery.builder()
                        .withQuery(builder -> builder
                                        .range(rangeQueryBuilder -> rangeQueryBuilder
                                                .field("publish_time")
                                                .gte(JsonData.of("2014-01-01"))
                                                .lte(JsonData.of("2017-12-31"))
                                        )
                                )
                        .build()
                , Book.class);
        iterateSearchHits(searchHits2, (searchHit, i) -> {
            Book book2 = searchHit.getContent();
            LOGGER.debug("result[{}] {}", i, book2);
            return null;
        });
    }

    private static <T> void iterateSearchHits(SearchHits<T> searchHits, BiFunction<SearchHit<T>, Integer, Void> logFunction) {
        long totalHits = searchHits.getTotalHits();
        LOGGER.debug("totalHits: {}", totalHits);
        List<SearchHit<T>> searchHitList = searchHits.getSearchHits();
        for(int i=0;i<searchHitList.size();i++) {
            SearchHit<T> searchHit = searchHitList.get(i);
            logFunction.apply(searchHit, i);
        }
    }

}
